EF框架操作postgresql,实现WKT类型坐标的插入,查询,以及判断是否相交
1.组件配置
首先,要下载.NET for Postgresql的驱动,npgsql,EF6,以及EntityFramework6.Npgsql,版本号 3.1.1.0.
由于是mvc项目,所以,把相应的配置文件写在web.config里面,如下:
1 <configSections> 2 <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> 3 <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> 4 </configSections>
由于项目数据的存储是用的MongoDB,此代码段必须添加在<configuration>标签下的第一个子节点,是对EF框架的引入声明.
<!--EF框架与Npgsql整合--> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v13.0" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> <provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql" /> </providers> </entityFramework>
此段配置是EF框架与npgsql的整合。
<system.data> <!--注册npgSql组件--> <DbProviderFactories> <remove invariant="Npgsql" /> <add name="Npgsql" invariant="Npgsql" description=".Net Framework Data Provider for Postgresql" type="Npgsql.NpgsqlFactory, Npgsql" /> <add name="dotConnect for PostgreSQL" invariant="Devart.Data.PostgreSql" description="Devart dotConnect for PostgreSQL" type="Devart.Data.PostgreSql.PgSqlProviderFactory, Devart.Data.PostgreSql, Version= 7.7.804.0, Culture=neutral, PublicKeyToken=09af7300eec23701"/> </DbProviderFactories> </system.data>
此段配置,是对npgsql组件的注册,缺失的话会报npgsql未注册的异常。
用nuget直接下载上述组件,这些都应该会自动生成配置文件,我之前是因为写了一个控制台程序进行尝试,mvc项目里的组件
都是直接引用的控制台程序里面的。
<!--Postgresql数据库的字符串连接信息--> <connectionStrings> <add name ="db" connectionString ="Server=localhost;Port=5432;Database=db;User Id=postgres;Password=123456;" providerName="Npgsql"/> </connectionStrings>
连接信息需要自己添加,不会生成。
2. 数据库连接
这里遇到了一个问题,明明配置文件中密码写的没问题,读到后台代码中时,ConnectString里总是没有密码,于是乎用笨方法,在c#代码里面自己在重写一遍ConnectString
public class dbFactory : DbContext 2 { 3 public dbFactory(string databaseName, bool isDoInitialize = false) 4 : base(databaseName) 5 { 6 if (!isDoInitialize) 7 { 8 Database.Connection.Open(); 9 Database.Connection.ConnectionString = "Server=127.0.0.1;Port=5432;Database=db;User Id=postgres;Password=123456"; 10 11 Database.SetInitializer<dbFactory>(null); 12 13 14 15 } 16 } 17 18 19 20 21 22 //public DbSet<Destination> Destination { set; get; } 23 public DbSet<PuKouMap> PuKouMap 24 { 25 set; 26 get; 27 28 } 29 public DbSet<Judyment> Judyment { set; get; } 30 }
而且必须要自己手动打开连接,否则初始化后连接状态一直是Closed,不知道有什么更好的方法。
1 [Table("PuKouMapDb", Schema = "public")] 2 public class PuKouMap 3 { 4 [Key] 5 public int Id { set; get; } 6 public int Type { set; get; } 7 public string ObjectId { set; get; } 8 public string Polygon { set; get; } 9 public string ZipName { set; get; } 10 public string FilePath { set; get; } 11 public string FileNames { set; get; } 12 public string ObjectName { set; get; } 13 }
要在实体类上面加一个注解,实体类对应表名写上,因为在sqlsever默认的架构师dbo,postgresql却是public,所以在这要改一下。
1 public class BaseDao 2 { 3 public static dbFactory db = null; 4 /// <summary> 5 /// 派生类实例化时加载基类构造函数,进行数据库连接 6 /// </summary> 7 static BaseDao() 8 { 9 db = new dbFactory("db"); 10 11 } 12 #region 得到建立连接后的数据操作接口 13 public dbFactory getDb() { 14 15 16 return db; 17 } 18 #endregion 19 }
1 public class QueryString 2 { 3 4 public static string Insert(PuKouMap p) { 5 String InsertAction = "INSERT INTO public.'PuKouMapDb' VALUES("+p.Type+","+p.ObjectId+","+"st_GeomFromText(" +"'"+ p.Polygon +"'"+",4326)"+","+p.ZipName+","+p.FilePath+","+p.FileNames+","+p.ObjectName+";)"; 6 return InsertAction; 7 } 8 #region 断句加空格 9 public static string GetPoKouMapByObjectIdString(String ObjectId) { 10 11 String CheckAction = "SELECT a.\"Id\",a.\"Type\",a.\"ObjectId\",ST_ASTEXT(a.\"Polygon\") AS \"Polygon\",a.\"ZipName\",a.\"FilePath\",a.\"FileNames\",a.\"ObjectName\" " 12 +"from public.\"PuKouMapDb\" as a "+ 13 "where " 14 +"a.\"ObjectId\"='"+ObjectId+"'"; 15 16 return CheckAction; 17 } 18 #endregion 19 public static string IsIntersects(String PolygonNew,String Geometry) { 20 21 string IsIntersectsAction = "SELECT ST_Intersects(st_GeomFromText(" + "'" + PolygonNew + "')" + "," +"'"+ Geometry +"'" +") AS \"TrueOrFalse\""; 22 return IsIntersectsAction; 23 } 24 25 26 27 }
postgresql的sql语句必须要注意的地方就是表名和字段名必须要加双引号,所以用了转义字符,插入直接用EF框架提供的Add(),方法就行了,会以坐标系缺省的情况插入进去.查询要用到ST_ASTEXT函数进行geometry类型向文本类型的转换,语句用EF框架的sqlQuery执行(感觉还不如用原生方法,做geomoetry分析,都必须用到postgis的空间分析函数,必须要写sql)
判断是否相交则用ST_Intersects函数对两个geometry类型进行判断,返回值是一个bool类型,由于EF框架没有找到衔接postgresql的操作,返回值貌似只有对象,所以自己写了一个bool值实体类。
public class Judyment { [Key] public bool TrueOrFalse { set; get; } }
相当于是一个存放结果的容器。应当注意sql语句中必须要写一个相同别名对应实体名。
新人发文,还请各位大佬指正。